
import libuv.uv ;

import 
	std.algorithm,
	std.array,
	std.conv,
	std.stdio;

import
	tango.io.device.Array,
	tango.stdc.stringz,
	tango.io.Stdout ,
	
	tango.math.random.Random,
	tango.net.device.Berkeley,
	tango.net.InternetAddress,
	tango.net.InternetAddress,
	Int	= tango.text.convert.Integer ,
	tango.core.Array ,
	tango.io.device.Array ,
	tango.io.device.File ;
	
alias File	= tango.io.device.File.File ;

struct _Struct {
	string		_name ;
	string[]	_fields ;
	
	static _Struct*[]	 list ;
	
	static void Load(alias S, string name = null )(string[] _exclude = null){
		_Struct* p	= new _Struct ;
		p._name	= S.stringof ;
		if( name !is null ) {
			p._name	= name ;
		}
		S	_s ;
		foreach(int i, c ; _s.tupleof ) {
			string field_name	= S.tupleof[i].stringof[ S.stringof.length + 3 ..$] ;
			bool	v	= true ;
			if( field_name.length > 2 && field_name[0] is '_' && field_name[1] is '_' ){
				v	= false ;
			}else if( _exclude !is null ) {
				if( contains( _exclude , field_name ) ){
					v	= false ;
				}
			}
			if( !v ) {
				continue ;
			}
			p._fields	~= field_name ;
		}
		list		~= p	;
	}
	
	static void GenTest(){
		auto bu	= new Array(1024, 1024) ;
		
		bu("#include <stddef.h>\n");
		bu("#include \"uv.h\"\n");
		bu("#define FSIZ(type, field) sizeof(((type *)0)->field)\n");
		bu("\n");
		
		bu("typedef struct _d_struct_field { char* name ; int size ; int off ; } _D_struct_field ; \n");
		bu("typedef struct _d_struct_info { char* name ; int size ; int field_count ; _D_struct_field* field_list ; } _D_struct_info ; \n");
		bu("typedef struct _d_struct_list { int struct_count ;  _D_struct_info* list ; } _D_struct_list ; \n");
		bu("\n");
		
		
		dump_struct(bu) ;
		dump_fields(bu) ;
		
		bu("UV_EXTERN void* get_uv_struct_info() {\n");
			bu("  static _D_struct_list struct_list_var = {0};\n") ;
			bu("  if( struct_list_var.struct_count == 0 ) { \n") ;
				foreach(int i, s ; list ) if( s._fields.length > 0 ) {
					bu("\td_struct_info_var[")( Int.toString(i) )("].field_list  = d_struct_field_")( Int.toString(i) )("; \n");
				}
				bu("\tstruct_list_var.struct_count = ")( Int.toString(list.length) )(" ; \n");
				bu("\tstruct_list_var.list 	= d_struct_info_var ; \n");
			bu("  }\n");
			bu("  return &struct_list_var ; \n");
		bu("}\n");
		
		File.set(`./uv-struct-info.c`, bu.slice );
		writeln( cast(string) bu.slice );
		File.set(`Z:/projects/libuv/src/uv-struct-info.c`, bu.slice );
	}
	
	static void dump_struct(Array bu){
		bu("static _D_struct_info d_struct_info_var[")( Int.toString(list.length) )("] = {\n") ;
		foreach( s ; list ){
			bu("\t{\"")(s._name)("\", sizeof(struct ")(s._name)("), ")( Int.toString(s._fields.length ) )("},\n");
		}
		space(bu);
		bu("};\n");
	}
	
	static void dump_fields(Array bu){
		foreach(int i, s ; list ) {
			if( s._fields.length is 0 ) {
				continue ;	
			}
			bu("static _D_struct_field d_struct_field_")(Int.toString(i))("[")( Int.toString( s._fields.length) )("] = {\n") ;
			foreach(int j, field_name ; s._fields ) {
				bu("\t{")
					("\"")(field_name)("\", ")
					("FSIZ(struct ")(s._name)(", ")(field_name)("), ")
					("offsetof(struct ")(s._name)(", ")(field_name)(") ")
				("},\n");
			}
			space(bu);
			bu("};\n");
		}
		bu("\n");
	}
	
	static void space(Array bu){
		if( bu is null ||  bu.slice .length is 0 ) return ;
		char* _p	= cast(char*) &( bu.slice )[ 0 ] ;
		char* p	= cast(char*) &( bu.slice )[ $ - 1 ] ;
		
		while(  p > _p ){
			if( *p is '\n' || *p is '\r' || *p is '\t' || *p is ' ' ){
				p-- ;
			}else{
				break ;
			}
		}
		
		if( *p is ',' ){
			*p	= ' ' ;
		}
		
	}
}

void main() {

	_Struct.Load!(_AFD_POLL_HANDLE_INFO)();
	_Struct.Load!(_AFD_POLL_INFO)();
	
	version(Windows){
		_Struct.Load!(addrinfoW)();
		_Struct.Load!(addrinfo)();
		_Struct.Load!(sockaddr)();
		_Struct.Load!(sockaddr_in)();
		_Struct.Load!(sockaddr_in6)();
		_Struct.Load!(sockaddr_storage)();
	}
	
	_Struct.Load!(uv_async_s)();
	_Struct.Load!(uv_buf_t)();
	
	_Struct.Load!(uv_check_s)();
	_Struct.Load!(uv_connect_s)();
	
	_Struct.Load!(uv_cpu_info_s)();
	_Struct.Load!(uv_cpu_times_s)();
 
	_Struct.Load!(uv_err_s)();
	_Struct.Load!(uv_fs_event_req_s)();
	_Struct.Load!(uv_fs_event_s)();
	_Struct.Load!(uv_fs_poll_s)();
	_Struct.Load!(uv_fs_s)();
	_Struct.Load!(uv_getaddrinfo_s)();
	_Struct.Load!(uv_handle_s)();
	_Struct.Load!(uv_idle_s)();
	_Struct.Load!(uv_interface_address_s)();
	_Struct.Load!(uv_loop_s)();
	_Struct.Load!(uv_once_s)();
	_Struct.Load!(uv_pipe_accept_s)();
	_Struct.Load!(uv_pipe_s)();
	_Struct.Load!(uv_poll_s)();
	_Struct.Load!(uv_prepare_s)();
	_Struct.Load!(uv_process_exit_s)();
	_Struct.Load!(uv_process_options_s)();
	_Struct.Load!(uv_process_s)();
	_Struct.Load!(uv_read_s)();
	_Struct.Load!(uv_req_s)();
	_Struct.Load!(uv_shutdown_s)();
	_Struct.Load!(uv_signal_s)();
	_Struct.Load!(uv_stdio_container_s)();
	_Struct.Load!(uv_stream_s)();
	_Struct.Load!(uv_tcp_accept_s)();
	_Struct.Load!(uv_tcp_s)();
	_Struct.Load!(uv_timer_s)();
	_Struct.Load!(uv_timer_tree_s, "uv_timer_tree_s")();
	_Struct.Load!(uv_tty_s)();
	_Struct.Load!(uv_udp_s)();
	_Struct.Load!(uv_udp_send_s)();
	_Struct.Load!(uv_work_s)();
	_Struct.Load!(uv_write_s)();
	
	_Struct.GenTest ;
}
